import { promises as fs } from 'fs';
import * as cp from 'child_process';
import * as path from 'path';
import * as os from 'os';
import chalk from 'chalk';
import linereader from 'line-reader';

/**
 * 创建并返回存放文件的临时目录
 */
export async function tempDir(): Promise<string> {
  const dir = path.join(os.homedir(), '.tagup');
  if (!await isExist(dir, true)) {
    await fs.mkdir(dir);
  }
  return dir;
}

/**
 * 判断路径是否存在
 * @param path 文件或文件夹路径
 * @param isDir 是否是文件夹，默认为文件
 */
export async function isExist(path: string, isDir = false): Promise<boolean> {
  try {
    const stat = await fs.stat(path);
    if (isDir) return stat.isDirectory();
    return true;
  } catch (err) {
    return false;
  }
}

/**
 * 读取文件内容
 * @param filepath 文件路径
 */
export async function readfile(filepath: string): Promise<string | null> {
  if (await isExist(filepath)) {
    return await fs.readFile(filepath, 'utf-8');
  }
  return null;
}

/**
 * a >= b
 */
export function compareVersion(a = '0.0.0', b = '0.0.0'): boolean {
  a = a.replace(/[^\d.]/, '');
  b = b.replace(/[^\d.]/, '');
  if (a === b) return true;

  const A = a.split('.').map(Number);
  const B = b.split('.').map(Number);
  for (let len = Math.max(A.length, B.length) - 1; len >= 0; len--) {
    const a1 = A[len] || 0;
    const b1 = B[len] || 0;
    if (a1 > b1) return true;
  }
  return false;
}

export function date(format = 'YYYY/MM/DD HH:mm:ss'): string {
  const d = new Date();
  function padLeft(val: number | string) {
    return String(val).padStart(2, '0');
  }

  const Y = d.getFullYear();
  const M = d.getMonth() + 1;
  const D = d.getDate();
  const H = d.getHours();
  const m = d.getMinutes();
  const s = d.getSeconds();

  return format
    .replace(/Y+/, String(Y))
    .replace(/M{2}/g, padLeft(M))
    .replace(/M/g, String(M))
    .replace(/D{2}/g, padLeft(D))
    .replace(/D/g, String(D))
    .replace(/H{2}/g, padLeft(H))
    .replace(/H/g, String(H))
    .replace(/m{2}/g, padLeft(m))
    .replace(/m/g, String(m))
    .replace(/s{2}/g, padLeft(s))
    .replace(/s/g, String(s));
}

export const exec = (cmd: string, options: cp.CommonOptions = {}): Promise<{ stdout: string; stderr: string }> => {
  return new Promise((resolve, reject) => {
    cp.exec(cmd, { timeout: 60 * 1000, ...options }, (err, stdout, stderr) => {
      if (err) return reject(err);
      resolve({ stdout, stderr });
    });
  });
}

export function send(message: string, type = true): void {
  const { REPO_NAME, TAG } = process.env;
  message !== null && process.send && process.send({ message, type, repoName: REPO_NAME, tag: TAG });
}

/**
 * 写入日志，并打印到终端
 */
async function log(type: string, repoName = '', tag = '', content: any): Promise<void> {
  if (typeof content === 'string') content = content.trim();
  if (content === '') return;

  const logPath = path.join(await tempDir(), `${repoName}-${date('YYYYMMDD')}-${type}.log`);
  const dt = date();
  console.log(chalk.blue(repoName), `[${chalk.grey(tag)}]:`, dt);
  console.log(type === 'error' ? chalk.red(content) : content, '\n');
  await fs.appendFile(logPath, `${repoName} [${tag}]: ${date()}\n${content}\n\n`, 'utf8');
}

export async function logInfo(repoName = '', tag = '', content: string): Promise<void> {
  await log('out', repoName, tag, content);
}

export async function logError(repoName = '', tag = '', content: unknown): Promise<void> {
  if (Object.prototype.toString.call(content) === '[object Object]') {
    content = JSON.stringify(content);
  }
  await log('error', repoName, tag, content);
}

/**
 * 判断known_hosts文件中是否含有domain
 */
export async function fileContain(domain: string): Promise<boolean> {
  const kh = path.join(os.homedir(), '.ssh/known_hosts');
  const exist = await isExist(kh);
  return new Promise((resolve) => {
    if (exist) {
      linereader.eachLine(kh, (line, last) => {
        if (line.indexOf(`${domain} ssh-rsa `) > -1) {
          resolve(true);
          return false;
        }
        if (last) resolve(false);
      });
    } else {
      resolve(false);
    }
  });
}